package com.example.gateway.controller;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.parser.OpenAPIV3Parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RestController
public class OpenApiAggregatorController {

    private static final Logger logger = LoggerFactory.getLogger(OpenApiAggregatorController.class);
    
    private final DiscoveryClient discoveryClient;
    private final WebClient webClient;
    
    // 服务名到API路径前缀的映射
    private static final Map<String, String> SERVICE_PATH_PREFIX = Map.of(
            "service-room-type", "/roomType",
            "service-room", "/room",
            "service-oss", "/oss",
            "service-check-in", "/checkIn",
            "service-payment", "/payment",
            "service-user", "/user"
    );

    public OpenApiAggregatorController(DiscoveryClient discoveryClient, WebClient.Builder webClientBuilder) {
        this.discoveryClient = discoveryClient;
        this.webClient = webClientBuilder.build();
    }

    @GetMapping("/v3/api-docs")
    public Mono<OpenAPI> aggregateOpenApi() {
        return Flux.fromIterable(discoveryClient.getServices())
                .filter(service -> !service.equalsIgnoreCase("gateway")) // 排除网关自身
                .flatMap(this::fetchServiceApiDoc)
                .collectList()
                .map(this::mergeOpenApiDocs);
    }

    private Mono<OpenAPI> fetchServiceApiDoc(String serviceId) {
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        if (instances.isEmpty()) {
            logger.warn("No instances found for service: {}", serviceId);
            return Mono.empty();
        }
        
        ServiceInstance instance = instances.get(0);
        String url = String.format("http://%s:%d/v3/api-docs", instance.getHost(), instance.getPort());
        
        logger.info("Fetching OpenAPI doc from: {}", url);
        
        return webClient.get()
                .uri(url)
                .retrieve()
                .bodyToMono(String.class)
                .map(json -> {
                    OpenAPI openAPI = new OpenAPIV3Parser().readContents(json).getOpenAPI();
                    // 设置API的标题为服务ID，便于后续处理
                    if (openAPI.getInfo() == null) {
                        openAPI.setInfo(new Info().title(serviceId));
                    } else {
                        openAPI.getInfo().title(serviceId);
                    }
                    return openAPI;
                })
                .doOnError(e -> logger.error("Error fetching API doc for service {}: {}", serviceId, e.getMessage()))
                .onErrorResume(e -> Mono.empty());
    }

    private OpenAPI mergeOpenApiDocs(List<OpenAPI> apis) {
        if (apis.isEmpty()) {
            logger.warn("No API docs found from services");
            OpenAPI emptyApi = new OpenAPI();
            emptyApi.setInfo(new Info()
                    .title("酒店管理系统API")
                    .version("1.0")
                    .description("没有找到任何服务的API文档"));
            return emptyApi;
        }
        
        OpenAPI merged = new OpenAPI();
        merged.setInfo(new Info()
                .title("酒店管理系统API")
                .version("1.0")
                .description("所有微服务的API聚合文档"));
        
        // 用于保存所有组件
        Map<String, Object> allComponents = new ConcurrentHashMap<>();
        
        apis.forEach(api -> {
            String serviceId = api.getInfo().getTitle();
            String pathPrefix = SERVICE_PATH_PREFIX.getOrDefault(serviceId, "/" + serviceId);
            
            // 处理Paths，添加服务名前缀
            if (api.getPaths() != null) {
                api.getPaths().forEach((path, pathItem) -> {
                    // 使用映射表中的路径前缀替换
                    String newPath = pathPrefix + path;
                    if (merged.getPaths() == null) {
                        merged.setPaths(new Paths());
                    }
                    merged.getPaths().addPathItem(newPath, pathItem);
                });
            }
            
            // 合并Components
            if (api.getComponents() != null) {
                if (merged.getComponents() == null) {
                    merged.setComponents(api.getComponents());
                } else {
                    // 合并schemas
                    if (api.getComponents().getSchemas() != null) {
                        api.getComponents().getSchemas().forEach((name, schema) -> {
                            merged.getComponents().addSchemas(serviceId + "_" + name, schema);
                        });
                    }
                    // 可以添加其他组件类型的合并逻辑
                }
            }
        });
        
        return merged;
    }
}